package com.suyang.syt.util;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;

public class R6Card {
	public interface mwReader extends Library {
		
		/**
		 * 设备操作函数 打开读卡器通讯端口
		 * @param name		串行口读卡器可取"COM1", "COM2", "COM3", "COM4"等,字母大小写无关	USB口读卡器可取"USB1", "USB2", "USB3", "USB4"等 
		 * @param devNo		返回的通设备标识符
		 * @param param1	串行口读卡器 波特率,9600/19200/57600/115200	USB口读卡器打开设备的模式 1：共享模式 2：独占模式
		 * @param param2	串行口读卡器校验位,可为'E' 偶校验, 'N' 无校验,无特殊要求,一般使用偶校验即可		USB口读卡器未使用，可设置为0
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_dev_openReader(byte[] name, IntByReference devNo, int param1, int param2);

		/**
		 * 设备操作函数 读取读写器版本号 
		 * @param devNo		返回的通设备标识符
		 * @param readerVer	存放获取到的版本号
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_dev_readVer(int devNo, byte[] readerVersion);

		/**
		 * 设备操作函数 蜂鸣器控制
		 * @param devNo		返回的通设备标识符
		 * @param beepTime	蜂鸣次数
		 * @param interval	蜂鸣间隔，每100ms一个单位 
		 * @param time		蜂鸣时间，每100ms一个单位
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_dev_beep(int devNo, int beepTime, int interval, int time);

		/**
		 * 设备操作函数 关闭读写器
		 * @param devNo		返回的通设备标识符
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_dev_closeReader(int devNo);

		/**
		 * 设备操作函数 射频天线复位 
		 * @param devNo		返回的通设备标识符
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_dev_reset(int devNo);

		/**
		 * 设备操作函数 指示灯控制 
		 * @param devNo		返回的通设备标识符
		 * @param ctrInfo	指示灯控制信息，长度1个字节，bit7对应指示灯1控制；bit6对应指示灯2控制，以此类推; 0关、1开  例如: 0x80: 绿灯亮，红灯灭
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_dev_led(int devNo, byte ctrInfo);
		
		/**
		 * 设备操作函数 读取读写器唯一的序列号
		 * @param devNo		返回的通设备标识符
		 * @param readerSn	存放收到的序列号
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_dev_readSn(int devNo, int readerSn);

		/**
		 * 卡片操作函数 对CPU卡复位
		 * @param devNo		返回的设备描述符
		 * @param ivCardSeat卡座编号  0：      接触式大卡座      1：      非接触式卡座       2—5：    扩展的第2--5个小CPU/PSAM卡座  
		 * @param infoATR	存放收到的应答信息，16进制字符串，以'\0'为结束标示
		 * @param atrLen	存放收到的应答信息的长度
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_cpu_reset(int devNo, int ivCardSeat, byte[] infoATR, IntByReference atrLen);

		/**
		 * 卡片操作函数 对CPU卡发送指令
		 * @param devNo		返回的设备描述符
		 * @param ivCardSeat卡座编号  0：      接触式大卡座      1：      非接触式卡座       2—5：    扩展的第2--5个小CPU/PSAM卡座  
		 * @param apduData	对接触式CPU卡发送的指令信息(相关指令请参考CPU卡COS手册)
		 * @param apduLen	对接触式CPU卡发送的指令信息长度  
		 * @param respData	返回的信息 
		 * @param respLen	返回的信息长度 
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_cpu_apdu(int devNo, int ivCardSeat, byte[] apduData, int apduLen, byte[] respData, IntByReference respLen);

		/**
		 * 卡片操作函数 对CPU卡下电
		 * @param devNo		返回的设备描述符
		 * @param ivCardSeat卡座编号  0：      接触式大卡座      1：      非接触式卡座       2—5：    扩展的第2--5个小CPU/PSAM卡座  
		 * @return			
		 */
		public int mw_cpu_powerDown(int devNo, int ivCardSeat);

		/**
		 * 卡片操作函数 打开mifare卡片
		 * @param devNo		返回的设备描述符
		 * @param openMode	打开模式：0x00  STD模式,只能寻到空闲状态下的卡片，被激活的卡片不会响应  
		 * 					0x01  ALL模式,所有卡片都能寻到，已经被激活的卡片将回到空闲状态后并重新被激活
		 * @param cardUid	返回的卡片序列号 
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_openCard(int devNo, byte openMode, byte[] cardUid);

		/**
		 * 卡片操作函数 关闭mifare卡片
		 * @param devNo		返回的设备描述符
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_closeCard(int devNo);
		
		/**
		 * 卡片操作函数 请求卡片 
		 * @param devNo		返回的设备描述符
		 * @param openMode	打开模式：0x00  STD模式,只能寻到空闲状态下的卡片，被激活的卡片不会响应  
		 * 					0x01  ALL模式,所有卡片都能寻到，已经被激活的卡片将回到空闲状态后并重新被激活
		 * @param cardType	返回的卡片类型Mifare 
		 * 					标准 1k           :0x0004 	Mifare 	标准 4k   : 0x0002
		 * 					Mifare Light     :0x0010	Mifare UtraLight : 0x0044
		 * 					CPU :            :0x0008
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_requestCard(int devNo, byte openMode, char cardType);

		/**
		 * 卡片操作函数 防冲突
		 * @param devNo		返回的设备描述符
		 * @param cardUid	返回的卡片序列号
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_anticoll(int devNo, byte cardUid);
		
		/**
		 * 卡片操作函数 选择卡片 
		 * @param devNo		返回的设备描述符
		 * @param cardUid	被选择的卡片序列号
		 * @param cardUidLen返回该卡片的容量
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_select(int devNo, byte cardUid, int cardUidLen);
		
		/**
		 * 卡片操作函数 验证卡片密码
		 * @param devNo		返回的设备描述符
		 * @param keyMode	密码类型,0-表示输入A密码,1-表示输入是B密码 
		 * @param sector	要验证的扇区号
		 * @param key		密码，以'\0'为结束的字符串,长度为12个字节，例如:"ffffffffffff"
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_authentication(int devNo, byte keyMode, int sector, byte[] key);

		/**
		 * 卡片操作函数 读数据
		 * @param devNo		返回的设备描述符
		 * @param blockNo	要读取的块号，S50卡取值为0～63、S70卡取值为0～255; 
		 * @param readData	读取的数据 
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_read(int devNo, int blockNo, byte[] readData);

		/**
		 * 卡片操作函数 写数据
		 * @param devNo		返回的设备描述符
		 * @param blockNo	要写入数据的块号 
		 * @param writeData	写入的数据
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_write(int devNo, int blockNo, byte[] writeData);

		/**
		 * 卡片操作函数 初始化值 
		 * @param devNo		返回的设备描述符
		 * @param blockNo	要初始化的块号 
		 * @param initValue	写入的数据，必须是已按照值存储格式格式化后的数据 
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_initVal(int devNo, int blockNo, int initValue);

		/**
		 * 卡片操作函数 读值
		 * @param devNo		返回的设备描述符
		 * @param blockNo	要读值的块号
		 * @param dstValue	读取的数值
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_readVal(int devNo, int blockNo, IntByReference dstValue);

		/**
		 * 卡片操作函数 增值 
		 * @param devNo		返回的设备描述符
		 * @param blockNo	要增值的块号
		 * @param value		增加的数值，必须是已按照值存储格式格式化后的数据
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_increment(int devNo, int blockNo, int value);

		/**
		 * 卡片操作函数 减值 
		 * @param devNo		返回的设备描述符
		 * @param blockNo	要减值的块号
		 * @param value		减少的数值，必须是已按照值存储格式格式化后的数据
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_decrement(int devNo, int blockNo, int value);

		/**
		 * 卡片操作函数 将某块的数据传入卡的内部寄存器中
		 * @param devNo		返回的设备描述符
		 * @param blockNo	寄存数据的块号
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_restore(int devNo, int blockNo);
		
		/**
		 * 卡片操作函数 将内部寄存器的数据传送到某一块中，进行此项操作必须验证该块的扇区密码
		 * @param devNo		返回的设备描述符
		 * @param blockNo	传送数据的块号 
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_transfer(int devNo, int blockNo);

		/**
		 * 卡片操作函数 将选定的卡片置于HALT模式，需要Request All将其唤醒
		 * @param devNo		返回的设备描述符
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_mifare_halt(int devNo);

		/**
		 * 工具函数 将ASCII编码的2个字节合成为一个16进制数  例如：输入数据为字符串"32",则转化0x32
		 * @param srcAsc	要转换的ASCII编码数据
		 * @param srcLen	ASCII数据长度 
		 * @param dstHex	转换后的HEX格式数据，该存储空间至少是 srcLen/2 个字节的长度.
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_ext_ascToHex(byte[] srcAsc, int srcLen, byte[] dstHex);

		/**
		 * 工具函数 将一个16进制数据转化为2个字节的ASCII。例如：输入数据为0X32，则转化后的数据为0x33,0x32,即字符串"32" 
		 * @param srcHex	要被转换的HEX格式数据
		 * @param srcLen	HEX数据长度
		 * @param dstAsc	转换后的ASCII格式数据，该存储空间至少是 srcLen*2 个字节的长度
		 * @return			等于0表示成功 不等于0表示失败错误代码
		 */
		public int mw_ext_hexToAsc(byte[] srcHex, int srcLen, byte[] dstAsc);
	}
	

	R6Card.mwReader epen = null;
	
	/**
	 * 返回的通设备标识符
	 */
	IntByReference devNo = new IntByReference();
	
	/**
	 * 存放收到的设备的序列号
	 */
	IntByReference readerSn = new IntByReference();

	public void loadLibrary() {
		epen = (R6Card.mwReader) Native.loadLibrary("mwCardReader",R6Card.mwReader.class);
		if (epen != null) {
			System.out.println("DLL加载成功！");
		} else {
			System.out.println("DLL加载失败！");
		}
	}

	public void readerCtrl() {
		int st = -1;
		byte[] USB = new byte[] { 'U', 'S', 'B', '1', 0 };
		st = epen.mw_dev_openReader(USB, devNo, 2, 0);
		if (st != 0) {
			System.out.println("打开设备失败！");
		} else {
			System.out.println("打开设备成功！");
			byte[] readerVersion = new byte[20];
			st = epen.mw_dev_readVer(devNo.getValue(), readerVersion);
			if (st != 0) {
				System.out.println("读版本号失败!");
			} else {
				String str = new String(readerVersion);
				System.out.println(str);
				st = epen.mw_dev_led(devNo.getValue(), (byte)0x80);
				if (st != 0) {
					System.out.println("指示灯控制失败!");
				} else {
					epen.mw_dev_beep(devNo.getValue(), 2, 2, 2);
				}
			}
		}

		

		
	}

	/**
	 * CPU卡操作
	 * @param ivCardSeat
	 */
	public void cpuCard(int ivCardSeat) {
		int st = -1;
		IntByReference atrLen = new IntByReference();
		byte[] infoATR = new byte[50];
		st = epen.mw_cpu_reset(devNo.getValue(), ivCardSeat, infoATR, atrLen);
		if (st != 0) {
			System.out.println("CPU卡复位失败！");
			return;
		} else {
			byte[] resetData = new byte[100];
			epen.mw_ext_hexToAsc(infoATR, atrLen.getValue(), resetData);
			String str = new String(resetData, 0, atrLen.getValue() * 2);
			System.out.println(str);
		}
		String cmd = "0084000008";
		byte[] apduData = new byte[10];
		epen.mw_ext_ascToHex(cmd.getBytes(), cmd.length(), apduData);
		byte[] respData = new byte[20];
		epen.mw_cpu_apdu(devNo.getValue(), ivCardSeat, apduData,
				cmd.length() / 2, respData, atrLen);
		if (st != 0) {
			System.out.println("CPU卡apdu失败！");
			return;
		} else {
			byte[] returnData = new byte[50];
			epen.mw_ext_hexToAsc(respData, atrLen.getValue(), returnData);
			String str = new String(returnData, 0, atrLen.getValue() * 2);
			System.out.println(str);
		}
		epen.mw_cpu_powerDown(devNo.getValue(), ivCardSeat);
	}

	// M1卡操作
	public void mifareCard() {
		int st = -1;
		int sector = 2;
		byte openMode = (byte) 1;
		byte[] cardUid = new byte[9];
		st = epen.mw_mifare_openCard(devNo.getValue(), openMode, cardUid);
		if (st != 0) {
			System.out.println("open card error!");
			return;
		} else {
			String str = new String(cardUid, 0, 8); // 返回的UID为8个字符
			System.out.println(str);
		}
		String key = "ffffffffffff";
		st = epen.mw_mifare_authentication(devNo.getValue(), (byte) 0, sector, key.getBytes());
		if (st != 0) {
			System.out.println("check key error!");
			return;
		}
		String wdata = "5e3d26e3630c4b533324f41d9ee6e04f";
		st = epen.mw_mifare_write(devNo.getValue(), sector * 5, wdata.getBytes());
		if (st != 0) {
			System.out.println("write data error!");
			return;
		}
		byte[] readData = new byte[17];
		st = epen.mw_mifare_read(devNo.getValue(), sector * 5, readData);
		if (st != 0) {
			System.out.println("read data error!");
			return;
		} else {
			String str = new String(readData, 0, 16);
			System.out.println(str);
		}
		int initValue = 1023;
		st = epen.mw_mifare_initVal(devNo.getValue(), sector * 5 + 1, initValue);
		if (st != 0) {
			System.out.println("初始化值 失败!");
			return;
		}
		int inValue = 435;
		st = epen.mw_mifare_increment(devNo.getValue(), sector * 5 + 1, inValue);
		if (st != 0) {
			System.out.println("加值 失败!");
			return;
		}
		epen.mw_mifare_transfer(devNo.getValue(), sector * 5 + 1);
		int deValue = 621;
		st = epen.mw_mifare_decrement(devNo.getValue(), sector * 5 + 1, deValue);
		if (st != 0) {
			System.out.println("减值 失败!");
			return;
		}
		epen.mw_mifare_transfer(devNo.getValue(), sector * 5 + 1);
		IntByReference value = new IntByReference();
		st = epen.mw_mifare_readVal(devNo.getValue(), sector * 5 + 1, value);
		if (st != 0) {
			System.out.println("读值 失败!");
			return;
		} else {
			System.out.println("读值成功！    " + String.valueOf(value.getValue()));
		}
	}
	
	public void readSn() {
		epen.mw_dev_readSn(devNo.getValue(), readerSn.getValue());
	}

	public void CloseReader() {
		epen.mw_dev_closeReader(devNo.getValue());
	}

	public static void main(String[] args) {
		R6Card machine = new R6Card();
		machine.loadLibrary();
		machine.readerCtrl();
		machine.readSn();
		//machine.cpuCard(1);
		machine.mifareCard();
		machine.CloseReader();
	}
}
